<script>
import { isObject } from '@vimi/utils-tool'
const getValueByFunction = (value, row) => (typeof value === 'function' ? value(row) : value)

// 操作按钮
const createOperationButtonComponent = (h, opts, row) => {
  const attrs = Object.assign(
    {
      type: 'text',
      class: 'py-0 px-2',
    },
    opts.attrs
  )
  const { class: clz, ...props } = attrs

  const children = []
  if (opts.icon) {
    children.push(h('i', { class: getValueByFunction(opts.icon, row) }))
  }
  if (opts.name) {
    children.push(h('span', null, getValueByFunction(opts.name, row)))
  }

  return h(
    'el-button',
    {
      props,
      directives: opts.directives,
      class: clz,
      nativeOn: {
        click: () => {
          const event = opts.event
          if (typeof event === 'function') {
            event(row)
          }
        },
      },
    },
    children
  )
}

// 带提示tooltip的按钮
const createTooltipButtonComponent = (h, opts, row, props = {}) => {
  const { tooltipProps } = props
  return h(
    'el-tooltip',
    {
      props: {
        ...tooltipProps,
        content: getValueByFunction(opts.content, row),
      },
    },
    [createOperationButtonComponent(h, opts, row)]
  )
}

// 操作列
const createOperationsComponent = (h, operations, row, props) => {
  function operationIfRender(ifRender) {
    if (ifRender === undefined) {
      return true
    }
    return typeof ifRender === 'function' ? ifRender(row) : ifRender
  }

  const components = operations
    .filter(item => operationIfRender(item.ifRender))
    .reduce((prev, curr) => {
      if (curr.content) {
        prev.push(createTooltipButtonComponent(h, curr, row, props))
      } else {
        prev.push(createOperationButtonComponent(h, curr, row))
      }
      return prev
    }, [])

  return h('div', components)
}

const createProcessComponent = (h, scope, column) => {
  const rawValue = scope.row[scope.column.property]
  const processValue = column.process(rawValue, scope.row, column)
  const {
    tag = 'div',
    attrs = {},
    value = rawValue,
  } = isObject(processValue) ? processValue : { value: processValue }
  return h(tag, attrs, value)
}

const createTruncateComponent = (h, scope, column) => {
  const rawValue = scope.row[scope.column.property]
  const { truncate } = column
  const attrs =
    typeof truncate === 'boolean'
      ? { class: truncate ? 'text-truncate' : '' }
      : { class: 'text-truncate--line', style: `--line-clamp: ${truncate || 1}` }
  return h(
    'el-tooltip',
    {
      props: {
        effect: 'light',
        content: rawValue,
      },
    },
    [h('div', attrs, rawValue)]
  )
}

export default {
  name: 'TableColumn',
  functional: true,
  props: {
    column: {
      type: Object,
      required: true,
    },
    effect: String,
    placement: String,
  },
  render(h, context) {
    const { column, effect = 'light', placement = 'bottom-start' } = context.props

    // 递归当前组件
    let children = null
    const childColumns = (column.columns || []).filter(item => !item.hidden)
    if (childColumns.length) {
      children = []
      for (const child of childColumns) {
        children.push(
          h('table-column', {
            props: { column: child, effect, placement },
          })
        )
      }
    }

    // 默认的渲染组件处理
    // slot、operations、process、render
    const scopedSlots = {}
    if (column.slot) {
      scopedSlots.default = column.scopedSlot
    } else if (column.operations) {
      scopedSlots.default = scope =>
        createOperationsComponent(h, column.operations, scope.row, {
          tooltipProps: { effect, placement },
        })
    } else if (column.process) {
      scopedSlots.default = scope => createProcessComponent(h, scope, column)
    } else if (column.truncate) {
      scopedSlots.default = scope => createTruncateComponent(h, scope, column)
    } else if (typeof column.render === 'function') {
      scopedSlots.default = scope => column.render(h, scope, column)
    }

    return h(
      'el-table-column',
      {
        props: column.attrs,
        scopedSlots,
      },
      children || context.children
    )
  },
}
</script>

<style lang="scss" scoped></style>
